package io.xxx.omni.sync.impl

import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.kuaishou.merchant.open.api.AccessTokenKsMerchantRequestSupport
import com.kuaishou.merchant.open.api.KsMerchantResponse
import com.kuaishou.merchant.open.api.client.AccessTokenKsMerchantClient
import com.kuaishou.merchant.open.api.request.KsMerchantOrderListRequest
import com.kuaishou.merchant.open.api.request.KsMerchantRefundListRequest
import com.kuaishou.merchant.open.api.response.KsMerchantOrderListResponse
import com.kuaishou.merchant.open.api.response.KsMerchantRefundListResponse
import io.xxx.omni.sync.Document
import io.xxx.omni.sync.Porter
import io.xxx.omni.sync.Store
import io.xxx.omni.util.offset
import org.springframework.stereotype.Component
import java.time.Duration
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId

/**
 * 快手
 */
@Component
abstract class KsPorter<T : AccessTokenKsMerchantRequestSupport<R>, R : KsMerchantResponse> : Porter() {

    override val platformCode = "kuaishou"

    override val duration: Duration? = Duration.ofDays(1)

    override fun pullAndSave(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?
    ): List<String> {
        var client = container["ksClient"]
        if (client == null) {
            client = AccessTokenKsMerchantClient(null, store.appKey, store.appSecret)
            container["ksClient"] = client
        }
        var cursor = ""
        val result = mutableListOf<String>()
        do {
            val request = buildRequest(store, startTime, endTime, cursor)
            request.accessToken = store.accessToken
            request.apiMethodVersion = 1
            val response = (client as AccessTokenKsMerchantClient).execute(request)
            if (!response.isSuccess) {
                throwException(request.apiMethodName, response.result, response.errorMsg)
            }
            val (documents, nextCursor) = buildDocuments(response)
            if (!documents.isNullOrEmpty()) {
                result.addAll(documents.map { it.sn!! })
            }
            save(store, documents)
            cursor = nextCursor
        } while (cursor != "nomore")
        return result
    }

    protected abstract fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        cursor: String
    ): T

    protected abstract fun buildDocuments(response: R): Pair<List<Document>, String>
}

@Component
class KsTradePorter : KsPorter<KsMerchantOrderListRequest, KsMerchantOrderListResponse>() {

    override val jobId = 1

    override fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        cursor: String
    ): KsMerchantOrderListRequest {
        val request = KsMerchantOrderListRequest()
        request.pageSize = 100
        request.type = 1
        request.sort = 1
        request.queryType = 2
        request.cpsType = 0
        request.beginTime = startTime.toInstant(offset).toEpochMilli()
        request.endTime = endTime.toInstant(offset).toEpochMilli()
        request.pcursor = cursor
        return request
    }

    override fun buildDocuments(response: KsMerchantOrderListResponse): Pair<List<Document>, String> {
        val data = response.merchantOrderListData
        val documents = data.orderInfoList.map {
            val modified = LocalDateTime.ofInstant(Instant.ofEpochMilli(it.updateTime), ZoneId.systemDefault())
            Document(it.oid.toString(), JSON.toJSON(it) as JSONObject, modified)
        }
        return documents to data.pcursor
    }
}

@Component
class KsRefundPorter : KsPorter<KsMerchantRefundListRequest, KsMerchantRefundListResponse>() {

    override val jobId = 2

    override fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        cursor: String
    ): KsMerchantRefundListRequest {
        val request = KsMerchantRefundListRequest()
        request.pageSize = 100
        request.type = 9
        request.sort = 1
        request.queryType = 2
        request.negotiateStatus = 1
        request.beginTime = startTime.toInstant(offset).toEpochMilli()
        request.endTime = endTime.toInstant(offset).toEpochMilli()
        request.pcursor = cursor
        return request
    }

    override fun buildDocuments(response: KsMerchantRefundListResponse): Pair<List<Document>, String> {
        val data = response.merchantRefundListData
        val documents = data.refundOrderInfoList.map {
            val modified = LocalDateTime.ofInstant(Instant.ofEpochMilli(it.updateTime), ZoneId.systemDefault())
            Document(it.refundId.toString(), it.oid.toString(), JSON.toJSON(it) as JSONObject, modified)
        }
        return documents to data.pcursor
    }
}